#include "CommoConnectionPool.h"
#include "public.h"

ConnectionPool *ConnectionPool::getConnectionPool()
{
    static ConnectionPool pool; // c++11后保证静态变量的创建的线程安全
    return &pool;
}

//读取配置文件

bool ConnectionPool::loadConfigFile()
{
    FILE *fp = fopen("./mysql.ini", "r");
    if (fp == nullptr)
    {
        LOG("mysql.ini file is not exist!");
        return false;
    }

    while (!feof(fp))
    {
        char line[1024] = {0};
        fgets(line, 1024, fp);
        string str = line;

        int idx = str.find('=', 0);
        if (idx == -1)
        {
            continue;
        }

        int endidx = str.find('\n', idx);
        string key = str.substr(0, idx);
        string value = str.substr(idx + 1, endidx - idx - 1);

        if (key == "ip")
        {
            _ip = value;
        }
        else if (key == "port")
        {
            _port = atoi(value.c_str());
        }
        else if (key == "username")
        {
            _username = value;
        }
        else if (key == "passwd")
        {
            _passwd = value;
        }
        else if (key == "dbname")
        {
            _dbname = value;
        }
        else if (key == "initSize")
        {
            _initSize = atoi(value.c_str());
        }
        else if (key == "maxSize")
        {
            _maxSize = atoi(value.c_str());
        }
        else if (key == "maxIdleTime")
        {
            _maxIdleTime = atoi(value.c_str());
        }
        else if (key == "connectionTimeOut")
        {
            _connectionTimeout = atoi(value.c_str());
        }
    }
    //成功获取配置
    cout << this->_initSize << endl;

    return true;
}

ConnectionPool::ConnectionPool()
{
    if (!loadConfigFile())
    {
        return;
    }

    //创建连接池
    for (int i = 0; i < _initSize; i++)
    {
        Connection *tmp = new Connection();
        if (!tmp->connect(_ip, _port, _username, _passwd, _dbname))
        {
            LOG("Connect error");
            exit(1);
        }
        tmp->refreshAliveTime();
        _connectionQue.push(tmp);
        _connectionCnt++;
    }

    //启动创建者线程
    thread produce(std::bind(&ConnectionPool::produceConnectionTask, this));
    produce.detach();
    /*
        https://blog.csdn.net/qq_38410730/article/details/103637778    std::bind
    */

    //启动定时线程,循环查询队列中的连接存活时间
    thread scanner(std::bind(&ConnectionPool::scannerConnectionTask, this));
    scanner.detach();
}

void ConnectionPool::produceConnectionTask()
{
    for (;;)
    {
        unique_lock<mutex> lock(_queueMutex); // unique_lock的使用  https://cloud.tencent.com/developer/article/1583807

        while (!_connectionQue.empty()) //当队列不为空的时候,就在这里循环
        {
            cout << 11 << endl;
            cv.wait(lock); //等待被消费者唤醒,唤醒后查询刚刚拿走的Connection是否为最后一个
        }
        //当队列为空时,表示连接已经被使用完了,我们需要查看当前Connection是否小于最大连接
        if (_connectionCnt < _maxSize)
        {
            //创建新的Connection并且存入队列尾部
            Connection *tmp = new Connection();
            tmp->connect(_ip, _port, _username, _passwd, _dbname);
            tmp->refreshAliveTime();
            _connectionQue.push(tmp); //新的Connection放入队尾
            _connectionCnt++;         //当前Connection++
        }

        //通知消费者线程进行消费
        cv.notify_all();
    }
}

/*
    返回一个智能指针(管理Connection)对象,用户只需要使用即可不用考虑释放问题,
    当智能指针被析构的时候会自动调用我们自定义的析构函数
*/

shared_ptr<Connection> ConnectionPool::getConnection()
{
    unique_lock<mutex> lock(_queueMutex);
    while (_connectionQue.empty())
    {
        if (cv_status::timeout == cv.wait_for(lock, chrono::milliseconds(_connectionTimeout)))
        {
            //申请的Connection等待了_connectionTimeout时间被返回
            if (_connectionQue.empty())
            {
                LOG("获取连接超时....");
                return nullptr;
            }
        }
    }
    // shared_ptr本身就是一个指针类型,所以模板类型为 Connection
    // 自定义析构函数
    shared_ptr<Connection> sp(_connectionQue.front(),
                              [&](Connection *_pcon)
                              {
                                  _pcon->refreshAliveTime();
                                  _connectionQue.push(_pcon);
                              });
    _connectionQue.pop();
    cv.notify_all(); //唤醒生产者,让他去查询当前队列是否为空
    return sp;
}

void ConnectionPool::scannerConnectionTask()
{
    for (;;)
    {
        //通过sleep模拟定时效果
        this_thread::sleep_for(chrono::seconds(_maxIdleTime));
        // cout << 22 << endl;
        //遍历队列
        unique_lock<mutex> lock(_queueMutex); //当一次循环结束后调用析构函数进行解锁操作
        while (!_connectionQue.empty())
        {
            Connection *p = _connectionQue.front();
            if (p->getAliveTime() >= (_maxIdleTime * 1000))
            {
                _connectionQue.pop();
                _connectionCnt--;
                delete p; //调用delete释放连接
            }
            else
            {
                break; //当有一个连接未满足条件,那么后续的连接也不会超时
            }
        }
    }
}